#include "tempreture_controller.h"
#include <QDebug>
#include <QDateTime>
#include <cmath>

Tempreture_Controller::Tempreture_Controller(QObject *parent)
    : QObject{parent}
{

    connect(CurveTimer,&QTimer::timeout,this,[=](){
        auto it = std::lower_bound(timeList.begin(), timeList.end(), CurveCount);
        int index = it - timeList.begin();

        if(index>0&&index<valueList.length()){
            float tr = (valueList[index]-valueList[index-1])/deltaTimeList[index];
            targetValue = targetValue+tr;
        }else if(index>=valueList.length()){
            CurveTimer->stop();
        }

        // qDebug()<<CurveType<<targetValue;

        if(CurveType=="power"){
            setPower(targetValue);
        }else{
            setTempretrue(targetValue);
        }

        CurveCount++;

    });
    connect(this,&Tempreture_Controller::plcErrOccuer,this,[=](){client->Disconnect();});
}

bool Tempreture_Controller::connectToPlc(QString PLCPort){
    char *ip = PLCPort.toLocal8Bit().data();
    uint i = client->ConnectTo(ip,0,1);
    if(i==0){
        connectedFlag = true;
        oldIP = PLCPort;
        CurveTimer->stop();
        return true;
    }else {
        connectedFlag = false;
        return false;
    }
}

bool Tempreture_Controller::hotStart(){
    int i = client->PlcHotStart();
    if(i==0) i = client->Disconnect();
    if(i==0) i = client->Connect();
    return i==0;
}

void Tempreture_Controller::disconnectToPlc(){
    CurveTimer->stop();
    openPowerControl(false);
    client->Disconnect();
    connectedFlag = false;
}

bool Tempreture_Controller::setDigitalOutput(int outputPort,bool flag)
{
    if(!connectedFlag)return false;

    byte oldRead;
    int i = client->ReadArea(S7AreaPA,0,0,1,S7WLByte,&oldRead);

    if(i!=0)i = client->ReadArea(S7AreaPA,0,0,1,S7WLByte,&oldRead);
    if(i!=0) return false;

    if(flag)
        oldRead |= (1 << outputPort);
    else
        oldRead &= ~(1 << outputPort);

    byte newWrite = oldRead;
    int j = client->WriteArea(S7AreaPA,0,0,1,S7WLByte,&newWrite);
    if(j!=0) j = client->WriteArea(S7AreaPA,0,0,1,S7WLByte,&newWrite);
    if(j!=0) return false;
    else return true;
}

bool Tempreture_Controller::readDigitalOutput(int outputPort){
    if(!connectedFlag)return false;

    byte oldRead;
    int i = client->ReadArea(S7AreaPA,0,0,1,S7WLByte,&oldRead);

    if(i!=0)i = client->ReadArea(S7AreaPA,0,0,1,S7WLByte,&oldRead);
    if(i!=0) return false;

    bool isSet = (oldRead & (1 << outputPort)) != 0;

    return isSet;
}


bool Tempreture_Controller::writeFloat(uint16_t uAddr, float fValue, int nDb)
{
    if(!connectedFlag)return false;

    float value = fValue;
    uint8_t buffer[4];
    memcpy(buffer, &value, sizeof(value));

    for(int i = 0; i < sizeof(float) / 2; ++i){
        std::swap(buffer[i], buffer[sizeof(float) - i - 1]);
    }

    int result = client->WriteArea(S7AreaDB, nDb, uAddr, 1, S7WLReal, buffer);

    if(result == 0){
        return true;
    } else {
        emit plcErrOccuer();
        return false;
    }
}

float Tempreture_Controller::readFloat(uint16_t uAddr, float &fValue, int nDb){
    uint8_t buffer[4];

    int result = client->ReadArea(S7AreaDB, nDb, uAddr, 1, S7WLReal, buffer);
    if(result != 0){
        emit plcErrOccuer();
        return false;
    }

    for(int i = 0; i < sizeof(float) / 2; ++i){
        std::swap(buffer[i], buffer[sizeof(float) - i - 1]);
    }

    memcpy(&fValue, buffer, sizeof(fValue));

    return fValue;
}


bool Tempreture_Controller::writeDB(uint16_t uAddr, int Value, int nDb){
    return true;
}

int Tempreture_Controller::readDB(uint16_t uAddr, int nDb){
    return 0;
}




//获取当前温度
float Tempreture_Controller::getCurrentTempretrue(){
    if(!connectedFlag)return -1;
    readFloat(12,currentTempreTrue,1);
    if(std::isnan(currentTempreTrue))
    {
        currentTempreTrue  = 0;
    }
    return currentTempreTrue;
}

//获取当前输出功率
float Tempreture_Controller::getCurrentPower(){
    if(!connectedFlag)return -1;
    readFloat(20,currentPower,1);

    if(std::isnan(currentPower))
    {
        currentPower  = 0;
    }
    return currentPower;
}

//高频感应机开始上电↓
bool Tempreture_Controller::openPowerControl(bool flag){
    if(!connectedFlag)return false;
    CurveTimer->stop();
    if(flag)
        setPower(235);
    else
        setPower(0);
    return setDigitalOutput(0, flag);
}


//设置输出功率
void Tempreture_Controller::setPower(float power){
    if(!connectedFlag)return;
    enablePidControll(false);

    if(!writeFloat(20,power,1))
    {
        disconnectToPlc();
        connectToPlc();
        writeFloat(20,power,1);
    }
    currentPower = getCurrentPower();
}

//设置目标温度
void Tempreture_Controller::setTempretrue(float targetTempretrue){
    // 写入目标值
    writeFloat(16,targetTempretrue,1);
    //开启pid
    enablePidControll(true);
}

bool Tempreture_Controller::setDigitalMemery(uint16_t uAddr, int bit, bool flag){
    if(!connectedFlag)return false;

    byte oldRead;
    int i = client->ReadArea(S7AreaDB,1,uAddr,1,S7WLByte,&oldRead);
    if(i!=0)i = client->ReadArea(S7AreaDB,1,uAddr,1,S7WLByte,&oldRead);
    if(i!=0) return false;

    if(flag)
        oldRead |= (1 << bit);
    else
        oldRead &= ~(1 << bit);

    byte newWrite = oldRead;
    int j = client->WriteArea(S7AreaDB,1,uAddr,1,S7WLByte,&newWrite);
    if(j!=0) client->WriteArea(S7AreaDB,1,uAddr,1,S7WLByte,&newWrite);

    if(j!=0) return false;
    else return true;
}

bool Tempreture_Controller::readDigitalMemery(uint16_t uAddr, int bit){
    if(!connectedFlag)return false;

    byte oldRead;
    int i = client->ReadArea(S7AreaDB,1,uAddr,1,S7WLByte,&oldRead);
    if(i!=0)i = client->ReadArea(S7AreaDB,1,uAddr,1,S7WLByte,&oldRead);
    if(i!=0) return false;

    return (oldRead & (1 << bit)) != 0;
}

//开启pid温度控制
void Tempreture_Controller::enablePidControll(bool enable){
    if(!connectedFlag)return;

    byte oldRead;
    int i = client->ReadArea(S7AreaDB,1,0,1,S7WLByte,&oldRead);
    if(i!=0)i = client->ReadArea(S7AreaDB,1,0,1,S7WLByte,&oldRead);

    if(i!=0) return;


    if(enable)
        oldRead |= (1 << 1);
    else
        oldRead &= ~(1 << 1);

    byte newWrite = oldRead;
    int j = client->WriteArea(S7AreaDB,1,0,1,S7WLByte,&newWrite);
    if(j!=0) client->WriteArea(S7AreaDB,1,0,1,S7WLByte,&newWrite);
}



//设置温度/功率曲线
void Tempreture_Controller::setCurve(QList<float> vl, QList<float> tl, QString type){
    CurveType = type;

    timeList.clear();
    int sum = 0;
    for (int i = 0; i < tl.size(); ++i) {
        sum += tl[i];
        timeList.push_back(sum);
    }

    valueList = vl;
    deltaTimeList = tl;

    CurveTimer->stop();
    CurveTimer->start(1000);
    CurveCount = 0;
    targetValue = valueList[0];

    // qDebug()<<valueList<<tl<<timeList;
}


